home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dc1 / cexp.cold < prev    next >
Text File  |  1994-02-04  |  19KB  |  782 lines

  1.  
  2. /*
  3.  *  CEXP.C
  4.  *
  5.  *  Expression Parser.    These routines generate an expression tree.
  6.  *
  7.  *  unary: ! ~ & * ++ -- [exp] (..,..)
  8.  *
  9.  *  binary: % %= & && &= * *= + += , - -= -> . / /= << <<= =
  10.  *        >> >>= ^ ^= | || |=
  11.  *                            precedence
  12.  *  boolean:    < <= == >= > !=
  13.  *                         postf: () [] -> .
  14.  *  special:    exp ? exp : exp          unary: ! ~ ++ -- - * & sizeof
  15.  *                         bin:   * / %
  16.  *  terminator: (exp)                    + -
  17.  *        varid                    << >>
  18.  *        tokid (procedure call?)         < <= > >=
  19.  *        constant                == !=
  20.  *                            &
  21.  *                            ^
  22.  *                            |
  23.  *                            &&
  24.  *                            ||
  25.  *                            ?:
  26.  *                            = += -= *= /= %= |= &= ^= >>= <<=
  27.  *                            ,
  28.  */
  29.  
  30. #include "defs.h"
  31.  
  32. #define LR    1        /*    left to right, else        */
  33. #define RL    2        /*    right to left            */
  34. #define QBIN    4        /*    binary operator, else unary */
  35. #define BLR    (LR|QBIN)
  36. #define BRL    (RL|QBIN)
  37.  
  38. #define XX    0    /*  don't care (situation never comes up)   */
  39.  
  40. static short ExpPrec[64] = EXPPREC;
  41.  
  42. Prototype short CompExp(short, Exp **, long);
  43. Prototype short CompBracedAssign(short, Type *, Exp **, short, short);
  44.  
  45. Local void PushOp(Exp **, Exp **, void (*)(Exp **), long, long);
  46. Local void PushAtom(Exp **, Exp **, void (*)(Exp **));
  47. Local void CombineOp(Exp **, Exp **);
  48.  
  49. Exp *HackTmpExp;        /*  free expression cache   */
  50.  
  51. short
  52. CompExp(short t, Exp **pexp, long commaok)
  53. {
  54.     short unary = 1;        /*  operator state  */
  55.     short notdone = 1;
  56.     short parens = 0;
  57.     short quests = 0;        /*  # of question marks for colons */
  58.     Exp   *opStack = NULL;    /*  operator stack  */
  59.     Exp   *atomStack = NULL;    /*  atom stack        */
  60.  
  61.  
  62.     if (t == TokSemi)
  63.     zerror(EFATAL_EXPECTED_EXP);
  64.  
  65.     *pexp = NULL;
  66.  
  67.     for (;;) {
  68.     if (unary) {        /*    construct quantity  */
  69.         switch(t) {
  70.         case TokNot:    /*  !exp    */
  71.         PushOp(&atomStack, &opStack, GenNot, 140, RL);
  72.         break;
  73.         case TokAnd:    /*  &exp    */
  74.         PushOp(&atomStack, &opStack, GenAddr, 140, RL);
  75.         opStack->ex_Token = TokAddr;
  76.         break;
  77.         case TokStar:    /*  *exp    */
  78.         PushOp(&atomStack, &opStack, GenInd, 140, RL);
  79.         break;
  80.         case TokPlPl:    /*  ++exp   */
  81.         PushOp(&atomStack, &opStack, GenPreInc, 140, RL);
  82.         opStack->ex_Token = TokPreInc;
  83.         break;
  84.         case TokMiMi:    /*  --exp   */
  85.         PushOp(&atomStack, &opStack, GenPreDec, 140, RL);
  86.         opStack->ex_Token = TokPreDec;
  87.         break;
  88.         case TokPl:     /*  +exp    */
  89.         break;
  90.         case TokMi:     /*  -exp    */
  91.         PushOp(&atomStack, &opStack, GenNeg, 140, RL);
  92.         break;
  93.         case TokTilde:    /*  ~exp    */
  94.         PushOp(&atomStack, &opStack, GenCompl, 140, RL);
  95.         break;
  96.         case TokSizeof:    /*  sizeof exp    */
  97.         t = GetToken();
  98.         if (t == TokLParen) {    /*  check sizeof(type)    */
  99.             Type *baseType;
  100.             Type *type;
  101.             Symbol *sym;
  102.             long  baseFlags;
  103.             long  regFlags;
  104.  
  105.             t = GetToken();
  106.  
  107.             switch(t) {
  108.             case TokStruct:
  109.             case TokEnum:
  110.             case TokUnion:
  111.             case TokTypeQual:
  112.             case TokRegQual:
  113.             case TokTypeId:
  114.             case TokTypeof:
  115.             t = CompType(t, &baseType, &baseFlags, ®Flags);
  116.             type = baseType;
  117.             t = CompTypeDeclarators(t, &type, &sym, baseFlags);
  118.             if (t != TokRParen)
  119.                 zerror(EFATAL_SYNTAX_ERROR_EXP);
  120.             t = GetToken();
  121.             PushAtom(&atomStack, &opStack, GenSizeof);
  122.             atomStack->ex_Type = type;
  123.             unary = 0;
  124.             continue;
  125.             default:
  126.             PushOp(&atomStack, &opStack, GenSizeof, 140, RL);
  127.             ++parens;
  128.             PushOp(&atomStack, &opStack, GenParen, 0, XX);
  129.             opStack->ex_Token = TokLParen;
  130.             continue;   /*    already have next token after paren */
  131.             }
  132.         }
  133.         PushOp(&atomStack, &opStack, GenSizeof, 140, RL);
  134.         continue;    /*  already have next token */
  135.  
  136.         case TokLParen:    /*  (exp)  or (type) or ()  */
  137.         {
  138.             Type *baseType;
  139.             Type *type;
  140.             Symbol *sym;
  141.             long  baseFlags;
  142.             long  regFlags;
  143.  
  144.             t = GetToken();
  145.  
  146.             switch(t) {     /*  (typecast)    */
  147.             case TokStruct:
  148.             case TokEnum:
  149.             case TokUnion:
  150.             case TokTypeQual:
  151.             case TokRegQual:
  152.             case TokTypeId:
  153.             case TokTypeof:
  154.             t = CompType(t, &baseType, &baseFlags, ®Flags);
  155.             type = baseType;
  156.             t = CompTypeDeclarators(t, &type, &sym, baseFlags);
  157.             if (t != TokRParen)
  158.                 zerror(EFATAL_SYNTAX_ERROR_EXP);
  159.             t = GetToken();
  160.             PushOp(&atomStack, &opStack, GenCast, 140, RL);
  161.             opStack->ex_Type = type;
  162.             opStack->ex_Token = TokCast;
  163.             continue;
  164.             case TokRParen:
  165.             PushAtom(&atomStack, &opStack, GenParen);
  166.             unary = 0;
  167.             t = GetToken();
  168.             continue;
  169.             default:        /*  (exp)   */
  170.             ++parens;
  171.             PushOp(&atomStack, &opStack, GenParen, 0, XX);
  172.             opStack->ex_Token = TokLParen;
  173.             continue;   /*    already have next symbol  */
  174.             }
  175.         }
  176.         /* not reached */
  177.         Assert(0);
  178.                 /*  terminator    */
  179.         case TokEnumConst:
  180.         LexIntConst = (long)LexData;
  181.         LexUnsigned = 0;
  182.         case TokIntConst:
  183.         PushAtom(&atomStack, &opStack, GenIntConst);
  184.         atomStack->ex_Stor.st_IntConst = LexIntConst;
  185.         atomStack->ex_Token = t;
  186.         if (LexUnsigned)
  187.             atomStack->ex_Stor.st_Flags |= SF_UNSIGNED;
  188.         unary = 0;
  189.         break;
  190.         case TokStrConst:
  191.         PushAtom(&atomStack, &opStack, GenStrConst);
  192.         atomStack->ex_StrConst = LexStrConst;
  193.         atomStack->ex_StrLen   = LexStrLen;
  194.         atomStack->ex_Token = t;
  195.         unary = 0;
  196.         break;
  197.         case TokFltConst:
  198.         PushAtom(&atomStack, &opStack, GenFltConst);
  199.         atomStack->ex_Stor.st_FltConst = LexStrConst;
  200.         atomStack->ex_Stor.st_FltLen   = LexStrLen;
  201.         atomStack->ex_Token = t;
  202.         atomStack->ex_Type  = LexData;
  203.         unary = 0;
  204.         break;
  205.         case TokVarId:
  206.         /*
  207.          *  If this is a global or external variable, NOT a procedure,
  208.          *  and not already dummied, then add a dummy semantic entry
  209.          *  and var structure to the highest block in the procedure.
  210.          *
  211.          *  we can't put it in lower blocks due to the possibility
  212.          *  of goto past the lea in case it's lea is stuck into a
  213.          *  register.
  214.          */
  215.         {
  216.             Var *var = (Var *)LexData;
  217.  
  218.             PushAtom(&atomStack, &opStack, GenVarRef);
  219.             atomStack->ex_Token = TokVarRef;
  220.             atomStack->ex_Symbol = LexSym;
  221.             atomStack->ex_Var  = var;
  222.             atomStack->ex_Var->Refs += BlockCost + 1;
  223.             unary = 0;
  224.         }
  225.         break;
  226.         case TokId:     /*  possible subroutine?    */
  227.         t = GetToken();
  228.         if (t != TokLParen) {
  229.             zerror(EERROR_UNDEFINED_SYMBOL, SymToString(LexSym));
  230.         }
  231.  
  232.         /*
  233.          *  create a variable as a reference to the procedure
  234.          *  specified returning an int.
  235.          */
  236.  
  237.         {
  238.             Var *var = AllocStructure(Var);
  239.  
  240.             var->Type = &DefaultProcType;
  241.             var->Sym  = LexSym;
  242.             var->Flags = TF_EXTERN;
  243.             var->LexIdx= LFBase->lf_Index;  /* XXX */
  244.  
  245.             BlockAddTop(var);
  246.             SemanticAddTop(LexSym, TokVarId, var); /* XXX */
  247.  
  248.             PushAtom(&atomStack, &opStack, GenVarRef);
  249.             atomStack->ex_Token = TokVarRef;
  250.             atomStack->ex_Symbol= LexSym;
  251.             atomStack->ex_Var    = var;
  252.             ++atomStack->ex_Var->Refs;
  253.         }
  254.         unary = 0;
  255.         continue;    /*  have token */
  256.         default:
  257.         notdone = 0;
  258.         break;
  259.         }
  260.     } else {
  261.         unary = 1;
  262.  
  263.         switch(t) {
  264.         case TokNotEq:    /*  boolean    */
  265.         case TokEqEq:
  266.         PushOp(&atomStack, &opStack, GenBoolCompareSame, 90, BLR);
  267.         opStack->ex_Token = t;
  268.         break;
  269.         case TokLt:
  270.         case TokLtEq:
  271.         case TokGtEq:
  272.         case TokGt:
  273.         PushOp(&atomStack, &opStack, GenBoolCompare, 100, BLR);
  274.         opStack->ex_Token = t;
  275.         break;
  276.         case TokPercentEq:
  277.         PushOp(&atomStack, &opStack, GenPercentEq, 20, BRL);
  278.         break;
  279.         case TokAndEq:
  280.         PushOp(&atomStack, &opStack, GenAndEq, 20, BRL);
  281.         break;
  282.         case TokStarEq:
  283.         PushOp(&atomStack, &opStack, GenStarEq, 20, BRL);
  284.         break;
  285.         case TokMiEq:
  286.         PushOp(&atomStack, &opStack, GenMiEq, 20, BRL);
  287.         break;
  288.         case TokDivEq:
  289.         PushOp(&atomStack, &opStack, GenDivEq, 20, BRL);
  290.         break;
  291.         case TokLtLtEq:
  292.         PushOp(&atomStack, &opStack, GenLtLtEq, 20, BRL);
  293.         break;
  294.         case TokGtGtEq:
  295.         PushOp(&atomStack, &opStack, GenGtGtEq, 20, BRL);
  296.         break;
  297.         case TokPlEq:
  298.         PushOp(&atomStack, &opStack, GenPlEq, 20, BRL);
  299.         break;
  300.         case TokEq:
  301.         PushOp(&atomStack, &opStack, GenEq, 20, BRL);
  302.         break;
  303.         case TokOrEq:
  304.         PushOp(&atomStack, &opStack, GenOrEq, 20, BRL);
  305.         break;
  306.         case TokCaratEq:
  307.         PushOp(&atomStack, &opStack, GenCaratEq, 20, BRL);
  308.         break;
  309.  
  310.         case TokAndAnd:
  311.         PushOp(&atomStack, &opStack, GenAndAnd, 50, BLR);
  312.         break;
  313.         case TokOrOr:
  314.         PushOp(&atomStack, &opStack, GenOrOr, 40, BLR);
  315.         break;
  316.  
  317.         case TokDiv:
  318.         PushOp(&atomStack, &opStack, GenDiv, 130, BLR);
  319.         break;
  320.         case TokPercent:
  321.         PushOp(&atomStack, &opStack, GenPercent, 130, BLR);
  322.         break;
  323.         case TokStar:
  324.         PushOp(&atomStack, &opStack, GenStar, 130, BLR);
  325.         break;
  326.         case TokMi:
  327.         PushOp(&atomStack, &opStack, GenMi, 120, BLR);
  328.         opStack->ex_Token = TokMi;
  329.         break;
  330.         case TokPl:
  331.         PushOp(&atomStack, &opStack, GenPl, 120, BLR);
  332.         opStack->ex_Token = TokPl;
  333.         break;
  334.  
  335.         case TokAnd:
  336.         PushOp(&atomStack, &opStack, GenAnd, 80, BLR);
  337.         break;
  338.         case TokOr:
  339.         PushOp(&atomStack, &opStack, GenOr, 60, BLR);
  340.         break;
  341.         case TokCarat:
  342.         PushOp(&atomStack, &opStack, GenXor, 70, BLR);
  343.         break;
  344.         case TokLtLt:
  345.         PushOp(&atomStack, &opStack, GenLShf, 110, BLR);
  346.         break;
  347.         case TokGtGt:
  348.         PushOp(&atomStack, &opStack, GenRShf, 110, BLR);
  349.         break;
  350.  
  351.         case TokQuestion:
  352.         PushOp(&atomStack, &opStack, GenQuestion, 30, BRL);
  353.         opStack->ex_Token = TokQuestion;
  354.         opStack->ex_Precedence = 0;
  355.         ++quests;
  356.         break;
  357.  
  358.         case TokColon:
  359.         if (quests == 0) {
  360.             notdone = 0;
  361.             break;
  362.         }
  363.         --quests;
  364.         /*
  365.          *  Combine opstack until the op is GenQuestion.  After
  366.          *  all is said and done the tree looks like:        :
  367.          *                           / \
  368.          *            a ? b : c          ?   c
  369.          *                         a b
  370.          */
  371.         while (opStack && opStack->ex_Token != TokQuestion)
  372.             CombineOp(&atomStack, &opStack);
  373.         if (opStack == NULL)
  374.             zerror(EFATAL, EFATAL_SYNTAX_ERROR_EXP);
  375.         CombineOp(&atomStack, &opStack);    /*    atom for a ? b    */
  376.         PushOp(&atomStack, &opStack, GenColon, 30, BRL);
  377.         break;
  378.  
  379.         /*
  380.          *    postfix operators, we stay in binary mode
  381.          */
  382.  
  383.         case TokLParen:
  384.         /*
  385.          *  Subroutine call.
  386.          */
  387.  
  388.         unary = 0;
  389.         t = GetToken();
  390.         {
  391.             Exp *exp = NULL;
  392.             Exp **pe = &exp;
  393.  
  394.             while (t && t != TokRParen) {
  395.             Exp *e;
  396.  
  397.             t = CompExp(t, pe, 0);
  398.             e = *pe;
  399.             pe = &e->ex_Next;
  400.             if (t != TokComma && t != TokRParen) {
  401.                 zerror(EFATAL_EXPECTED_COMMACLOSE);
  402.                 break;
  403.             }
  404.             if (t == TokComma)
  405.                 t = GetToken();
  406.             }
  407.             PushOp(&atomStack, &opStack, GenCall, 150, LR);
  408.             opStack->ex_ExpR = exp;
  409.             opStack->ex_Token= TokCall;
  410.         }
  411.         break;
  412.         case TokRParen:
  413.         unary = 0;
  414.         if (parens == 0) {
  415.             notdone = 0;
  416.             break;
  417.         }
  418.         --parens;
  419.         /*
  420.          *  Combine until we find the GenParen
  421.          */
  422.         while (opStack && opStack->ex_Token != TokLParen)
  423.             CombineOp(&atomStack, &opStack);
  424.         if (opStack == NULL)
  425.             zerror(EFATAL_SYNTAX_ERROR_EXP);
  426.         CombineOp(&atomStack, &opStack);    /*  now have atom for (exp) */
  427.         break;
  428.         case TokComma:
  429.         unary = 1;
  430.         if (parens == 0 && commaok == 0) {
  431.             notdone = 0;
  432.             break;
  433.         }
  434.         PushOp(&atomStack, &opStack, GenComma, 10, BLR);
  435.         break;
  436.         case TokPlPl:   /*    exp++    */
  437.         unary = 0;
  438.         PushOp(&atomStack, &opStack, GenPosInc, 150, LR);
  439.         opStack->ex_Token = TokPosInc;
  440.         break;
  441.         case TokMiMi:
  442.         unary = 0;
  443.         PushOp(&atomStack, &opStack, GenPosDec, 150, LR);
  444.         opStack->ex_Token = TokPosDec;
  445.         break;
  446.         case TokStrInd:
  447.         case TokStrElm:
  448.         unary = 0;
  449.         {
  450.             void (*func)(Exp **) = ((t == TokStrInd) ? GenStructInd : GenStructElm);
  451.  
  452.             PushOp(&atomStack, &opStack, GenStructInd, 150, LR);
  453.             t = GetToken();
  454.             if (t != TokId && /* t != TokLabelId && */ t != TokVarId && t != TokTypeId && t != TokEnumConst)
  455.             zerror(EFATAL_EXPECTED_STRUCT_TAG);
  456.             opStack->ex_Func = func;
  457.             opStack->ex_Symbol = LexSym;
  458.         }
  459.         break;
  460.         case TokLBracket:
  461.         unary = 0;
  462.         {
  463.             Exp *exp;
  464.  
  465.             t = CompExp(GetToken(), &exp, 1);
  466.             if (t != TokRBracket)
  467.             zerror(EERROR_EXPECTED_CLOSE_BRACKET);
  468.             PushOp(&atomStack, &opStack, GenArray, 150, LR);
  469.             opStack->ex_ExpR = exp;
  470.         }
  471.         break;
  472.         default:
  473.         notdone = 0;
  474.         break;
  475.         }
  476.     }
  477.     if (notdone) {
  478.         t = GetToken();
  479.         continue;
  480.     }
  481.     break;
  482.     }
  483.     while (opStack)
  484.     CombineOp(&atomStack, &opStack);
  485.     if (atomStack == NULL)
  486.     zerror(EFATAL_SYNTAX_ERROR_EXP);
  487.     if (parens)
  488.     zerror(EFATAL_EXPECTED_CLOSE_PARENS, parens);
  489.     if (atomStack->ex_Next)
  490.     zerror(EFATAL_SYNTAX_ERROR_EXP);
  491.     atomStack->ex_Next = NULL;
  492.     *pexp = atomStack;
  493.  
  494.     return(t);
  495. }
  496.  
  497. /*
  498.  *  precedence of 0 is for parenthesized expressions and never combines.
  499.  */
  500.  
  501. Local  void
  502. PushOp(patomStack, popStack, genFunc, precedence, order)
  503. Exp **patomStack;
  504. Exp **popStack;
  505. void (*genFunc)(Exp **);
  506. long precedence;
  507. long order;
  508.  
  509. {
  510.     Exp *exp;
  511.  
  512.     /*
  513.      *    If precedence then pop stack until get entry with lower precedence,
  514.      *    equal precedence breaks out only for left-to-right operations.
  515.      *    Parsing : in a ?: expression ignores precedence until ? is found
  516.      *    again.
  517.      */
  518.  
  519.     if (precedence) {
  520.     for (exp = *popStack; exp; exp = *popStack) {
  521.         if (precedence > exp->ex_Precedence)
  522.         break;
  523.         if (precedence == exp->ex_Precedence && (order & RL))
  524.         break;
  525.         CombineOp(patomStack, popStack);
  526.     }
  527.     }
  528.     exp = AllocTmpStructure(Exp);
  529.     exp->ex_Precedence = precedence;
  530.     exp->ex_Order = order;
  531.     exp->ex_Func = genFunc;
  532.     exp->ex_Next = *popStack;
  533.     exp->ex_LexIdx = LFBase->lf_Index;
  534.     *popStack = exp;
  535. }
  536.  
  537. Local  void
  538. PushAtom(patomStack, popStack, genFunc)
  539. Exp **patomStack;
  540. Exp **popStack;
  541. void (*genFunc)(Exp **);
  542. {
  543.     Exp *exp;
  544.  
  545.     if (HackTmpExp) {
  546.     exp = HackTmpExp;
  547.     setmem(exp, sizeof(Exp), 0);
  548.     HackTmpExp = NULL;
  549.     } else {
  550.     exp = AllocTmpStructure(Exp);
  551.     }
  552.  
  553.     exp->ex_Func = genFunc;
  554.     exp->ex_Next = *patomStack;
  555.     exp->ex_LexIdx = LFBase->lf_Index;
  556.     exp->ex_Flags= 0;
  557.     *patomStack = exp;
  558. }
  559.  
  560. Local  void
  561. CombineOp(patomStack, popStack)
  562. Exp **patomStack;
  563. Exp **popStack;
  564. {
  565.     Exp *exp = *popStack;    /*  get op  */
  566.     Exp *e1;
  567.     Exp *e2;
  568.  
  569.     if (exp == NULL)
  570.     zerror(EFATAL_SYNTAX_ERROR_EXP);
  571.     if ((e1 = *patomStack) == NULL)
  572.     zerror(EFATAL_SYNTAX_ERROR_EXP);
  573.  
  574.     if (exp->ex_Order & QBIN) {
  575.     e2 = e1->ex_Next;
  576.     if (e2 == NULL)
  577.         zerror(EFATAL_SYNTAX_ERROR_EXP);
  578.     *patomStack = e2->ex_Next;
  579.     exp->ex_ExpL = e2;
  580.     exp->ex_ExpR = e1;
  581.     exp->ex_Flags = 0;
  582.     /*exp->ex_Flags = (e1->ex_Flags | e2->ex_Flags) & EF_CALL;*/
  583.  
  584.     } else {
  585.     *patomStack = e1->ex_Next;
  586.     exp->ex_ExpL = e1;
  587.     exp->ex_Flags = 0;
  588.  
  589.     if (exp->ex_Token == TokCall && e1->ex_Token == TokVarRef) {
  590.         char prgno[16];
  591.         PragNode *pragma_call;
  592.  
  593.         if (pragma_call = TestPragmaCall(e1->ex_Var, prgno)) {
  594.         /*
  595.          *  Append base variable reference - A6 to end of
  596.          *  argument list.
  597.          */
  598.         Exp *ex = zalloc(sizeof(Exp));
  599.         Exp **pexp;
  600.         Symbol *sym = MakeSymbol(pragma_call->pn_Sym->Name, pragma_call->pn_Sym->Len, TokId, NULL);
  601.         Var *var = sym->Data;
  602.  
  603.         if (sym->LexId != TokVarId)
  604.             yerror(exp->ex_LexIdx, EFATAL_PRAGMA_BASE_UNDEF, sym->Len, sym->Name);
  605.  
  606.         for (pexp = &exp->ex_ExpR; e1 = *pexp; pexp = &e1->ex_Next)
  607.             ;
  608.         ex->ex_Func = GenVarRef;
  609.         ex->ex_Token = TokVarRef;
  610.         ex->ex_Symbol = sym;
  611.         ex->ex_Var = sym->Data;
  612.         ex->ex_Flags |= EF_SPECIAL;
  613.         ++ex->ex_Var->Refs;
  614.         *pexp = ex;
  615.         }
  616.     }
  617.     }
  618.     *popStack = exp->ex_Next;
  619.     exp->ex_Next = *patomStack;
  620.     *patomStack = exp;
  621. }
  622.  
  623. /*
  624.  *  Parse a braced expression.    An open brace refers to an explcit
  625.  *  downlevel while an expression may cause zero or more implicit
  626.  *  downlevel's.
  627.  *
  628.  *  exp->ex_Token is set to TokExpAssBlock for downlevel exp's
  629.  *  exp->ex_ExpL is the base of a list of expressions linked via ex_Next
  630.  */
  631.  
  632. short
  633. CompBracedAssign(short t, Type *type, Exp **pexp, short lbraced, short commaok)
  634. {
  635.     Exp *exp;
  636.     long **caBase;
  637.     long index = 0;
  638.  
  639.     /*
  640.      *    create downlevel
  641.      */
  642.  
  643.     *pexp = exp = AllocTmpStructure(Exp);
  644.     pexp = &exp->ex_ExpL;
  645.     exp->ex_Type = type;
  646.     exp->ex_Token = TokExpAssBlock;
  647.     exp->ex_LexIdx = LFBase->lf_Index;
  648.     exp->ex_Func  = GenBracedAssign;
  649.     caBase = &exp->ex_ConstAry;
  650.  
  651.     for (;;) {
  652.     Type *subType;
  653.  
  654.     if (type->Id == TID_STRUCT) {
  655.         if (index >= type->Args)
  656.         break;
  657.         subType = type->Vars[index]->Type;
  658.     } else if (type->Id == TID_UNION) {
  659.         if (index)
  660.         break;
  661.         subType = type->Vars[0]->Type;
  662.     } else if (type->Id == TID_ARY) {
  663.         subType = type->SubType;
  664.         if (type->Size && index >= type->Size / subType->Size)
  665.         break;
  666.     } else {
  667.         subType = type;
  668.     }
  669.     if (subType->Id == TID_UNION || subType->Id == TID_STRUCT || subType->Id == TID_ARY) {
  670.         /*
  671.          *    level-down
  672.          */
  673.  
  674.         if (t == TokLBrace) {
  675.         t = CompBracedAssign(GetToken(), subType, pexp, 1, 1);
  676.         if (t != TokRBrace)
  677.             zerror(EERROR_TOO_MANY_INITIALIZERS);
  678.         t = GetToken();
  679.  
  680.         if (t == TokComma)
  681.             t = GetToken();
  682.         } else {
  683.         t = CompBracedAssign(t, subType, pexp, 0, 1);
  684.         }
  685.         ++index;
  686.         pexp = &(*pexp)->ex_Next;
  687.         if (t == TokRBrace || t == TokSemi)
  688.         break;
  689.     } else {
  690.         /*
  691.          *    terminal case for subType
  692.          *
  693.          *    A right-brace here may terminate the sequence, possible
  694.          *    unto multiple levels.
  695.          */
  696.  
  697.         if (t == TokRBrace || t == TokSemi)
  698.         break;
  699.  
  700.         if (t == TokStrConst && type->Id == TID_ARY && subType->Size == 1) {
  701.         Exp *sexp;
  702.  
  703.         t = CompExp(t, pexp, 0);
  704.         sexp = *pexp;
  705.         Assert(sexp->ex_Token == TokStrConst);
  706.         index += sexp->ex_StrLen;
  707.  
  708.         /*
  709.          *  quietly delete the terminating \0 if string
  710.          *  overruns array.
  711.          */
  712.  
  713.         if (type->Size) {
  714.             if (index > type->Size) {
  715.             if (index - 1 == type->Size) {
  716.                 --index;
  717.                 --sexp->ex_StrLen;
  718.             } else {
  719.                 sexp->ex_StrLen -= (index - type->Size);
  720.                 index = type->Size;
  721.                 zerror(EERROR_ARRAY_CANNOT_HOLD_STRING);
  722.             }
  723.             } else if (index < type->Size && lbraced == 0) {
  724.             /*
  725.              *  If no { } was used to explicitly specify
  726.              *  initializers for this array, the string will
  727.              *  force the array to be terminated & zero filled
  728.              */
  729.  
  730.             long newLen = type->Size - index + sexp->ex_StrLen;
  731.             char *new = talloc(newLen);
  732.             movmem(sexp->ex_StrConst, new, sexp->ex_StrLen);
  733.  
  734.             sexp->ex_StrConst = new;
  735.             sexp->ex_StrLen = newLen;
  736.             index = type->Size;
  737.             }
  738.         }
  739.         pexp = &(*pexp)->ex_Next;
  740.         } else {
  741.         /*
  742.          *  This is the nominal core, and where all the memory is
  743.          *  eaten up for statically initialized arrays.  Simple
  744.          *  integer constants are optimized (so we do not allocate
  745.          *  an entire Exp structure for each constant).
  746.          */
  747.  
  748.         t = CompExp(t, pexp, 0);
  749.         if (pexp == &exp->ex_ExpL && (*pexp)->ex_Token == TokIntConst) {
  750.             long *captr = talloc(sizeof(long) * 2);
  751.             Exp  *caexp = *pexp;
  752.  
  753.             *caBase = captr;
  754.             captr[1] = caexp->ex_Stor.st_IntConst;
  755.  
  756.             caBase = (long **)&captr[0];
  757.             HackTmpExp = caexp;
  758.             *pexp = NULL;
  759.         } else {
  760.             pexp = &(*pexp)->ex_Next;
  761.         }
  762.         ++index;
  763.         }
  764.  
  765.         if (t == TokComma) {
  766.         if (commaok == 0)
  767.             break;
  768.         t = GetToken();
  769.         }
  770.     }
  771.     }
  772.     *pexp = NULL;
  773.     *caBase = NULL;
  774.     HackTmpExp = NULL;        /*    don't leave stale cache */
  775.  
  776.     if (type->Id == TID_ARY && type->Size == 0)
  777.     type->Size = index * type->SubType->Size;
  778.  
  779.     return(t);
  780. }
  781.  
  782.